package com.chengshi.shop.controller.mobile.wechat;

import com.chengshi.shop.model.member.Member;
import com.chengshi.shop.model.order.Order;
import com.chengshi.shop.model.order.OrderPayment;
import com.chengshi.shop.service.member.MemberService;
import com.chengshi.shop.service.order.OrderPaymentService;
import com.chengshi.shop.service.order.OrderService;
import com.chengshi.shop.service.shop.ShopService;
import com.chengshi.shop.util.EnumUtil;
import com.chengshi.shop.util.MessageUtils;
import com.chengshi.shop.util.SessionUtils;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayBaseResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.util.Date;
import java.util.HashMap;

/**
 * 微信登录模块
 *
 * @author xuxinlong
 * @version 2017年07月20日
 */
@Api(tags ="微信调用相关接口")
@RestController
@RequestMapping(value = "/mobile/wechat")
public class MobileWechatController {
    @Resource
    private WxMpService wxMpService;
    @Resource
    private WxPayService wxPayService;
    @Resource
    private MemberService memberService;
    @Resource
    private OrderService orderService;
    @Resource
    private ShopService shopService;
    @Resource
    private OrderPaymentService orderPaymentService;


    @Value("${wechat.mp.host}")
    private String host;
    @Value("${wechat.pay.appSecret}")
    private String appsecret;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 微信验证登录
     *
     * @param request
     * @return
     */
    @ApiOperation("微信验证登录")
    @GetMapping(value = "/wxLogin")
    public void wxLogin(HttpServletRequest request, HttpServletResponse response, @RequestParam String requestURI) throws IOException {
        response.setContentType("text/html; charset=utf-8");
        String code = request.getParameter("code");
        String serverUrl = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort();
        if (code == null) {
            Member member = SessionUtils.getMember();
            if (member != null) {
                response.sendRedirect(serverUrl + requestURI);
            } else {
                // 构造获取授权链接
                String url = wxMpService.oauth2buildAuthorizationUrl(
                        host + "/mobile/wechat/wxLogin?requestURI=" + serverUrl + requestURI,
                        WxConsts.OAuth2Scope.SNSAPI_USERINFO, "");
                response.sendRedirect(url);
            }
        } else {
            try {
                WxMpOAuth2AccessToken oauth2AccessToken = wxMpService.oauth2getAccessToken(code);
                // 授权信息获取用户
                WxMpUser wxMpUser = wxMpService.getUserService().userInfo(oauth2AccessToken.getOpenId());
                //新用户注册
                Member member = memberService.getMemberByOpenId(wxMpUser.getOpenId());
                if (member == null) {
                    member = new Member();
                    member.setOpenId(wxMpUser.getOpenId());
                }
                member.setSex(wxMpUser.getSexId().byteValue());
                member.setHeadImg(wxMpUser.getHeadImgUrl());
                member.setName(wxMpUser.getNickname());
                member.setCountry(wxMpUser.getCountry());
                member.setProvince(wxMpUser.getProvince());
                member.setCity(wxMpUser.getCity());
                member.setSubscribe(wxMpUser.getSubscribe());
                memberService.saveMember(member);
                SessionUtils.setMember(memberService.getMemberByMemberId(member.getMemberId()));
                response.sendRedirect(requestURI);
            } catch (WxErrorException e) {
                response.getWriter().write("微信登录认证失败" + e.getMessage());
                this.logger.error("\n接收到来自微信登录认证失败：" + e.getMessage());
            }
        }
    }

    /**
     * 检查登录接口
     *
     * @return
     */
    @ApiOperation("检查是否登录")
    @GetMapping(value = "checkLogin")
    public HashMap<String, Object> checkLogin() {
        HashMap<String, Object> retMap = MessageUtils.success("已登录");
        try {
            Member member = SessionUtils.getMember();
            if (member != null) {
                retMap.put("member", member);
            } else {
                retMap.put("errorCode", "NOLOGIN");
                retMap.put("errorText", "未登录");
            }
        } catch (Exception e) {
            retMap = MessageUtils.error("查询失败");
        }
        return retMap;
    }

    /**
     * 获取微信JsapiSignature
     *
     * @param pageUrl
     * @return
     */
    @ApiOperation("获取微信JsapiSignature")
    @GetMapping(value = "/getConfig")
    public HashMap<String, Object> getConfig(@RequestParam String pageUrl) {
        HashMap<String, Object> retMap = MessageUtils.success();
        try {
            //当前页面的路径
            WxJsapiSignature wxJsapiSignature = wxMpService.createJsapiSignature(pageUrl);
            retMap.put("appId", wxJsapiSignature.getAppId());
            retMap.put("nonceStr", wxJsapiSignature.getNonceStr());
            retMap.put("signature", wxJsapiSignature.getSignature());
            retMap.put("timestamp", wxJsapiSignature.getTimestamp());
            retMap.put("url", wxJsapiSignature.getUrl());
        } catch (Exception e) {
            retMap = MessageUtils.error();
        }
        return retMap;
    }

    /**
     * 返回前台H5调用JS支付所需要的参数，公众号支付调用此接口
     *
     * @param orderId
     * @return
     */
    @ApiOperation("返回前台H5调用JS支付所需要的参数，公众号支付调用此接口")
    @PostMapping("/getWxPayInfo")
    public HashMap<String, Object> getPayInfo(@RequestParam Integer orderId) {
        HashMap<String, Object> retMap = MessageUtils.success();
        try {
            Member member = SessionUtils.getMember();
            Order order = orderService.getOrderByOrderId(orderId);
            if (order.getStatus() != EnumUtil.ORDER_STATUS.待付款.getValue().byteValue()) {
                retMap = MessageUtils.error("订单已支付");
                return retMap;
            }
            BigDecimal finalMoney = order.getTotalAmount().add(order.getPostage()).subtract(order.getPayed());
            WxPayUnifiedOrderRequest payInfo = WxPayUnifiedOrderRequest.newBuilder()
                    .openid(member.getOpenId())
                    .outTradeNo(order.getOrderNum())
                    .totalFee(WxPayBaseRequest.yuanToFee(finalMoney.toString()))
                    .body(shopService.getShopConfig("SHOP_NAME") + "-订单号" + order.getOrderNum())
                    .tradeType(WxPayConstants.TradeType.JSAPI)
                    .spbillCreateIp(InetAddress.getLocalHost().getHostAddress())
                    .notifyURL(host + "/mobile/wechat/getWxOrderNotify")
                    .build();
            WxPayMpOrderResult result = this.wxPayService.createOrder(payInfo);
            HashMap<String, Object> configMap = new HashMap<>();
            configMap.put("appId", result.getAppId());
            configMap.put("timeStamp", result.getTimeStamp());
            configMap.put("nonceStr", result.getNonceStr());
            configMap.put("package", result.getPackageValue());
            configMap.put("signType", result.getSignType());
            configMap.put("paySign", result.getPaySign());
            retMap.put("payInfo", configMap);
        } catch (Exception e) {
            logger.error("微信支付失败！订单orderId：{},原因:{}", orderId, e.getMessage());
            retMap = MessageUtils.error("支付失败，请稍后重试！");
        }
        return retMap;
    }

    /**
     * 支付回调
     *
     * @param request
     * @return
     */
    @ApiOperation("回调支付接口")
    @PostMapping("/getWxOrderNotify")
    public String getWxOrderNotify(HttpServletRequest request) {
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            WxPayOrderNotifyResult result = wxPayService.parseOrderNotifyResult(xmlResult);
            // 验证结果正确
            String orderNum = result.getOutTradeNo();
            String totalFee = WxPayBaseResult.feeToYuan(result.getTotalFee());
            Order order = orderService.getOrderByOrderNum(orderNum);
            if (order.getStatus().intValue() == EnumUtil.ORDER_STATUS.待付款.getValue()) {
                order.setPayTime(new Date());
                // 添加支付明细表中，实际支付的部分
                OrderPayment orderPayment = new OrderPayment();
                orderPayment.setOrderId(order.getOrderId());
                orderPayment.setMoney(new BigDecimal(totalFee));
                orderPayment.setPaymentMethod(EnumUtil.PAYMENT_METHOD.微信支付.getValue().byteValue());
                orderPayment.setContent("微信支付（订单：" + order.getOrderNum() + "）");
                orderPaymentService.saveOrderPayment(orderPayment, order);
            }
            //自己处理订单的业务逻辑，需要判断订单是否已经支付过，否则可能会重复调用
            return WxPayNotifyResponse.success("处理成功!");
        } catch (Exception e) {
            logger.error("微信回调结果异常,异常原因{}", e.getMessage());
            return WxPayNotifyResponse.fail(e.getMessage());
        }
    }
}
